library(GTFShift)
#> Warning: replacing previous import 'GTFSwizard::read_gtfs' by
#> 'tidytransit::read_gtfs' when loading 'GTFShift'
#> Warning: replacing previous import 'GTFSwizard::write_gtfs' by
#> 'tidytransit::write_gtfs' when loading 'GTFShift'

Introduction

Public transit analysis takes advantage of the standardized GTFS format. However, its provision by operator makes it difficult for network aggregated analysis, considering connectivity and multimodality. GTFShift::unify proposes a simple solution to this problem, generating an aggregated GTFS file given several instances of these.

Download GTFS files

Data source

The gathering of the GTFS files can be simplified by using public archives like transitfeeds.com or transit.land.

This library offers a small database with a compilation of GTFS files for Portuguese operators. It is a CSV file, available at extdata/gtfs_sources_pt.csv, and has the following attributes:

  • ID, a string unique identifier of the region/city the GTFS file applies to;
  • LastUpdate, the date at which this database entry was last updated;
  • ReferenceDate, a representative Wednesday that falls within the GTFS calendar;
  • URL, the URL at which the GTFS file is available;
  • GTFSDocs, the URL to the page that documents the operator GTFS.
data <- read.csv(system.file("extdata", "gtfs_sources_pt.csv", package = "GTFShift"))
summary(data)
#>       ID             LastUpdate        ReferenceDate          URL           
#>  Length:24          Length:24          Length:24          Length:24         
#>  Class :character   Class :character   Class :character   Class :character  
#>  Mode  :character   Mode  :character   Mode  :character   Mode  :character  
#>      Type             GTFSDocs        
#>  Length:24          Length:24         
#>  Class :character   Class :character  
#>  Mode  :character   Mode  :character
data[,]
#>             ID LastUpdate ReferenceDate
#> 1           cp 2025-02-01    2025-02-05
#> 2        autna 2025-02-01    2025-02-05
#> 3          AML 2025-02-01    2025-02-05
#> 4     barreiro 2025-02-01    2025-02-05
#> 5      cascais 2025-02-01    2025-02-05
#> 6       lisboa 2025-02-01    2025-02-05
#> 7  metroLisboa 2025-02-01    2025-02-05
#> 8     fertagus 2025-02-01    2025-02-05
#> 9        braga 2025-02-01    2025-02-05
#> 10        stcp 2025-02-01    2025-02-05
#> 11  metroPorto 2025-02-01    2025-02-05
#> 12       CIMMT 2025-02-01    2025-02-05
#> 13        AMAL 2025-02-01    2025-02-05
#> 14        faro 2025-02-01    2025-02-05
#> 15      tavira 2025-02-01    2025-02-05
#> 16   albufeira 2025-02-01    2025-02-05
#> 17       loule 2025-02-01    2025-02-05
#> 18       lagos 2025-02-01    2025-02-05
#> 19       olhao 2025-02-01    2025-02-05
#> 20    portimao 2025-02-01    2025-02-05
#> 21     funchal 2025-02-01    2025-02-05
#> 22       CIMRL 2025-02-01    2025-02-05
#> 23      leiria 2025-02-01    2025-02-05
#> 24     lousada 2025-02-01    2025-02-05
#>                                                                                                                                                                     URL
#> 1                                                                                                                                   https://publico.cp.pt/gtfs/gtfs.zip
#> 2                                                                                      https://drive.google.com/uc?export=download&id=1gah1x10RyFu7gJPweBcCXPd9vcFJFQ7c
#> 3                                                                                                                               https://api.carrismetropolitana.pt/gtfs
#> 4                                                                                                     https://www.tcbarreiro.pt/front/files/sample_gtfs/GTFS-TCB_24.zip
#> 5                                                                                  https://drive.google.com/u/0/uc?id=13ucYiAJRtu-gXsLa02qKJrGOgDjbnUWX&export=download
#> 6                                                                                                                  https://gateway.carris.pt/gateway/gtfs/api/v2.8/GTFS
#> 7                                                                                                           https://www.metrolisboa.pt/google_transit/googleTransit.zip
#> 8                                                                                                                  https://www.fertagus.pt/GTFSTMLzip/Fertagus_GTFS.zip
#> 9                                                                                                                            https://tub.pt/developer/gtfs/feed/tub.zip
#> 10 https://opendata.porto.digital/dataset/5275c986-592c-43f5-8f87-aabbd4e4f3a4/resource/1e0f4315-3694-42b0-a8ce-5218ad4742e5/download/horarios_gtfs_stcp_06_01_2025.zip
#> 11                                                                             https://www.metrodoporto.pt/metrodoporto/uploads/document/file/693/google_transit_v2.zip
#> 12                                                                                     https://drive.google.com/uc?export=download&id=1v9eGjezOzbaBQi-Aa5c15tZXcSiiDwqA
#> 13                                                                                     https://drive.google.com/uc?export=download&id=1CM8O4ndsfSJhka42SxFUZ9eB-wE10NqX
#> 14                                                                                     https://drive.google.com/uc?export=download&id=1xNHjM7yl-SS1jCkGrvIBBlOhUkFfNBjY
#> 15                                                                                     https://drive.google.com/uc?export=download&id=1C2KBOVsbm__ymWDgU1bXGbP0Gv3D2yo5
#> 16                                                                                     https://drive.google.com/uc?export=download&id=1tkKV40lQlFcLiJhq8SwZQdxNVjFclRCA
#> 17                                                                                     https://drive.google.com/uc?export=download&id=1w92h129CWNSoImBRZQOWT6KRPzSFwJ42
#> 18                                                                                     https://drive.google.com/uc?export=download&id=1aPfsxHqopxxcjV8HlRzImzxh_a6zRxGp
#> 19                                                                                     https://drive.google.com/uc?export=download&id=1X5uXAYJ5ItxMhrnDZSz3v9-U3kgL6QbJ
#> 20                                                                                     https://drive.google.com/uc?export=download&id=1Ii02y25MCOilAaQixsZNs1rcgdvNoYCs
#> 21                                                                                                                   http://www.horariosdofunchal.pt/google_transit.zip
#> 22                                                                                     https://drive.google.com/uc?export=download&id=192Qat2jJKyv5hhO8T3eVT70M5NB0dtXC
#> 23                                                                                     https://drive.google.com/uc?export=download&id=1NqcOk8IrlV73TBonJAxpzIUTjaAjF27M
#> 24                                                                                                       https://dadosabertos.cm-lousada.pt/datasets/GTFS_CIMTS_UT3.zip
#>             Type
#> 1  Long distance
#> 2  Long distance
#> 3    Inter-urban
#> 4          Urban
#> 5          Urban
#> 6          Urban
#> 7          Urban
#> 8          Urban
#> 9          Urban
#> 10         Urban
#> 11         Urban
#> 12   Inter-urban
#> 13   Inter-urban
#> 14         Urban
#> 15         Urban
#> 16         Urban
#> 17         Urban
#> 18         Urban
#> 19         Urban
#> 20         Urban
#> 21         Urban
#> 22   Inter-urban
#> 23         Urban
#> 24   Inter-urban
#>                                                                                                                                  GTFSDocs
#> 1                                                                                             https://www.transit.land/operators/o-eyc-cp
#> 2                                                                                https://www.transit.land/operators/o-ez-autnatransportes
#> 3                                                                                              https://github.com/carrismetropolitana/api
#> 4                                                                                                              https://www.tcbarreiro.pt/
#> 5                                                                          https://dadosabertos.cascais.pt/pt_PT/dataset/gtfs-mobicascais
#> 6                 https://gateway.carris.pt/apiui/#!/apis/2c05b837-1c8e-4b34-85b8-371c8edb344b/pages/d7f1c190-908d-4615-b1c1-90908d4615f5
#> 7                                                                                https://www.transit.land/operators/o-eyckr-metrodelisboa
#> 8                                                                                      https://www.transit.land/operators/o-eyce-fertagus
#> 9                                                                                                               https://tub.pt/downloads/
#> 10 https://opendata.porto.digital/de/dataset/horarios-paragens-e-rotas-em-formato-gtfs-stcp/resource/1e0f4315-3694-42b0-a8ce-5218ad4742e5
#> 11                                                                                                  https://www.metrodoporto.pt/pages/337
#> 12                                                                                          https://www.transit.land/operators/o-e-rmtejo
#> 13                                                                                          https://www.transit.land/operators/o-ey-vizur
#> 14                                                                                               https://www.transit.land/feeds/f-eyd-pxm
#> 15                                                                                    https://www.transit.land/operators/o-eyd-sobeedesce
#> 16                                                                                          https://www.transit.land/operators/o-eyd-giro
#> 17                                                                                      https://www.transit.land/operators/o-eyd-apanhame
#> 18                                                                                         https://www.transit.land/operators/o-ey9-aonda
#> 19                                                                                 https://www.transit.land/operators/o-eyd-circuitoolhao
#> 20                                                                                       https://www.transit.land/operators/o-ey9-vaievem
#> 21                                                                                    https://www.transit.land/operators/o-etgc-hf~urbano
#> 22                                                                                          https://www.transit.land/operators/o-ez-rdlis
#> 23                                                                                         https://www.transit.land/operators/o-ez1-rdlis
#> 24                                                                          https://nap-portugal.imt-ip.pt/nap/multimodalsupplydetail/195

Download and validate integrity

GTFShift library offers a method to download and fix any integrity violations at GTFS files: GTFShift::download(). It fixes inconsistencies on the stop_times.txt and missing shapes.txt files.

# DOWNLOAD GTFS and store it locally
gtfs_local <- lapply(data[c(6,8),]$ID, function(ID) {
  return(GTFShift::download(data$URL[data$ID == ID], sprintf("database/transit/%s_gtfs.zip", ID)))
})
#> Downloading GTFS file for https://gateway.carris.pt/gateway/gtfs/api/v2.8/GTFS...
#> Downloading GTFS file for https://www.fertagus.pt/GTFSTMLzip/Fertagus_GTFS.zip...

Unify GTFS

The unification is performed through GTFShift::unify(), producing a single GTFS instance, saved as a ZIP file. Option generateTransfers enables the generation of transfers.txt, aggregating close stops, even if from different GTFS.

# Load GTFS
library(GTFSwizard)
gtfs_list <- lapply(gtfs_local, function(location) {
  return(GTFSwizard::read_gtfs(location))
})

# Perform unification
gtfs_united_path <- GTFShift::unify(gtfs_list, "database/transit/gtfs_unified.zip", generateTransfers=TRUE)
#> 1. Starting merge process...
#> > Carris
#> > Merged with 175 routes, 63313 trips and 2330 stops...
#> > Fertagus
#> > Merged with 178 routes, 63573 trips and 2344 stops...
#> 2. Done! Storing result to database/transit/gtfs_unified.zip...
#> 3. Generating transfers...
#> ▶ Unzipping GTFS archive✔ Unzipped GTFS archive  
#> Warning: This feed contains no transfers.txt 
#>   A transfers.txt table may be constructed with the 'gtfs_transfer_table' function
#> ▶ Extracting GTFS feed
#> Warning in data.table::fread(flist[f], integer64 = "character", showProgress =
#> FALSE, : Attempt to override column 2 <<date>> of inherent type 'float64' down
#> to 'int32' ignored. Only overrides to a higher type are currently supported. If
#> this was intended, please coerce to the lower type afterwards.
#> ✔ Extracted GTFS feed 
#> ▶ Converting stop times to seconds✔ Converted stop times to seconds 
#> > Done! Storing result to database/transit/gtfs_unified.zip...
#> FINISHED :)

Distribute

It can be displayed using mapview.

library(mapview)

gtfs_united <- GTFSwizard::read_gtfs(gtfs_united_path)
#> Warning in data.table::fread(fs::path(tmpdir, filename), select =
#> fields_classes, : Attempt to override column 9 <<start_date>> of inherent type
#> 'float64' down to 'int32' ignored. Only overrides to a higher type are
#> currently supported. If this was intended, please coerce to the lower type
#> afterwards.
#> Warning in data.table::fread(fs::path(tmpdir, filename), select =
#> fields_classes, : Attempt to override column 10 <<end_date>> of inherent type
#> 'float64' down to 'int32' ignored. Only overrides to a higher type are
#> currently supported. If this was intended, please coerce to the lower type
#> afterwards.
#> Warning in data.table::fread(fs::path(tmpdir, filename), select =
#> fields_classes, : Attempt to override column 2 <<date>> of inherent type
#> 'float64' down to 'int32' ignored. Only overrides to a higher type are
#> currently supported. If this was intended, please coerce to the lower type
#> afterwards.
mapview::mapview(GTFSwizard::get_shapes_sf(gtfs_united$shapes))
mapview::mapview(GTFSwizard::get_stops_sf(gtfs_united$stops))